﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Resources;
using System.Reflection;
using System.Xml;
using System.Xml.Serialization;
using System.Text;

using Microsoft.BizTalk.Bam.EventObservation;
using Microsoft.BizTalk.Message.Interop;
using Microsoft.BizTalk.Component.Interop;
using Microsoft.BizTalk.Streaming;
using Microsoft.BizTalk.XPath;

using Software41.Tracking.BAM;
using Software41.Tracking.BAM.Adapters;

namespace Software41.TrackingExample.PipelineComponents
{
    [ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
    [ComponentCategory(CategoryTypes.CATID_Any)]
    [System.Runtime.InteropServices.Guid("C423FBCA-2934-426c-8802-743AF35C2C58")]
    public partial class EndProcessTraceInfo :
                           IBaseComponent,
                            IComponentUI,
                            Microsoft.BizTalk.Component.Interop.IComponent,
                            IPersistPropertyBag
    {
        #region Private Properties
         private ResourceManager resourceManager =
            new ResourceManager("Software41.TrackingExample.PipelineComponents.EndProcessTraceInfo", Assembly.GetExecutingAssembly());
        
        private string _processId = String.Empty;
        #endregion

        #region PublicProperties

        private bool _allowEndStep = false;
        public bool AllowEndStep
        {
            get { return _allowEndStep; }
            set { _allowEndStep = value; }
        }

        private bool _allowEndProcess = false;
        public bool AllowEndProcess
        {
            get { return _allowEndProcess; }
            set { _allowEndProcess = value; }
        }

        #endregion

        #region IBaseComponent
        // <summary>
        /// Name of the component
        /// </summary>
        [Browsable(false)]
        public string Name
        {
            get { return resourceManager.GetString("COMPONENTNAME", System.Globalization.CultureInfo.InvariantCulture); }
        }

        /// <summary>
        /// Version of the component
        /// </summary>
        [Browsable(false)]
        public string Version
        {
            get { return resourceManager.GetString("COMPONENTVERSION", System.Globalization.CultureInfo.InvariantCulture); }
        }
        /// <summary>
        /// Description of the component
        /// </summary>
        [Browsable(false)]
        public string Description
        {
            get
            {
                return this.resourceManager.GetString("COMPONENTDESCRIPTION", System.Globalization.CultureInfo.InvariantCulture);
            }
        }
        #endregion

        #region IComponentUI
        [Browsable(false)]
        public IntPtr Icon
        {
            get
            {
                return ((System.Drawing.Bitmap)(this.resourceManager.GetObject("COMPONENTICON", System.Globalization.CultureInfo.InvariantCulture))).GetHicon();
            }
        }


        public System.Collections.IEnumerator Validate(object projectSystem)
        {
            return null;
        }
        #endregion

        #region IComponent
        public IBaseMessage Execute(IPipelineContext pContext, IBaseMessage pInMsg)
        {
            ProcessTraceInfo process = null;
            IEventStream eventStream = null;
            try
            {
                string contextNamespace = "http://Software41.TrackingExample.CtxProps";

                if (this.AllowEndProcess)
                {
                    //if we are allowed to end the Process, check the message context to
                    //see if the process is active
                    bool isProcessActive = (bool)pInMsg.Context.Read("IsProcessActive", contextNamespace);

                    if (isProcessActive)
                    {
                        string processId = (string)pInMsg.Context.Read("ProcessId", contextNamespace);

                        var contextStream = pContext.GetEventStream();
                        eventStream = new EventStreamAdapter(contextStream);

                        //begin the process with the passed in name
                        process = new ProcessTraceInfo(processId, eventStream);

                        if (process != null)
                        {
                            var logDetail = process.AddLogDetail();
                            logDetail.AddDetail(String.Format("End Process Id: {0}", process.ProcessInfoId));

                            //see if we have an active step to end
                            if (this.AllowEndStep)
                            {
                                bool isStepActive = (bool)pInMsg.Context.Read("IsStepActive", contextNamespace);

                                if (isStepActive)
                                {
                                    string stepInfoId = (string)pInMsg.Context.Read("StepInfoId", contextNamespace);

                                    var stepInfo = new StepInfo(stepInfoId, eventStream);
                                    logDetail.AddDetail(String.Format("End Step Id: {0}",stepInfoId));

                                    stepInfo.End(true, "DummyMessage", "<Message>Hello World</Message>");
                                }
                            }

                            if (logDetail != null)
                            {
                                logDetail.End();
                            }

                            process.End(true);
                            eventStream.Flush();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                if (process != null)
                {
                    process.AddException(ex);
                    process.End(false);
                    eventStream.Flush();
                }
            }
            return pInMsg;
        }
        #endregion

        #region IPersistPropertyBag
        public void GetClassID(out Guid classID)
        {
            classID = new Guid("543747D8-7C17-4e4b-9BE6-49B081B41B01");
        }

        public void InitNew()
        {
            throw new NotImplementedException();
        }

        public void Load(IPropertyBag propertyBag, int errorLog)
        {
            object val = this.ReadPropertyBag(propertyBag, "AllowEndProcess");

            if (val != null)
            {
                this.AllowEndProcess = (bool)val;
            }

            val = this.ReadPropertyBag(propertyBag, "AllowEndStep");

            if (val != null)
            {
                this.AllowEndStep = (bool)val;
            }
        }

        public void Save(IPropertyBag propertyBag, bool clearDirty, bool saveAllProperties)
        {
            this.WritePropertyBag(propertyBag, "AllowEndProcess", this.AllowEndProcess);
            this.WritePropertyBag(propertyBag, "AllowEndStep", this.AllowEndStep); 
        }
        #endregion

        #region utility functionality
        /// <summary> 
        /// Reads property value from property bag 
        /// </summary> 
        /// <param name="pb">Property bag</param> 
        /// <param name="propName">Name of property</param> 
        /// <returns>Value of the property</returns> 
        private object ReadPropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName)
        {
            object val = null;
            try
            {
                pb.Read(propName, out val, 0);
            }
            catch (System.ArgumentException)
            {
                return val;
            }
            catch (System.Exception e)
            {
                throw new System.ApplicationException(e.Message);
            }
            return val;
        }

        /// <summary> 
        /// Writes property values into a property bag. 
        /// </summary> 
        /// <param name="pb">Property bag.</param> 
        /// <param name="propName">Name of property.</param> 
        /// <param name="val">Value of property.</param> 
        private void WritePropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName, object val)
        {
            try
            {
                pb.Write(propName, ref val);
            }
            catch (System.Exception e)
            {
                throw new System.ApplicationException(e.Message);
            }
        }
        #endregion 
    }
}
